package top.saodisheng;

import java.io.File;
import java.util.List;
import java.util.Scanner;

/**
 * Description:
 * 目标函数 y = a0 + (a1 * x1) + (a2 * x2)
 * 其中y表示子女的身高，x1表示父亲的升高，x2表示母亲的身高
 * @author 扫地生_saodisheng
 */
public class Main {
    private static int ML;      // 系数矩阵的行数
    private static int MM = 3;      // 系数矩阵的列数
    private static double[] BoyParams = new double[MM];      // 存放参数解向量（男生）
    private static double[] GirlParams = new double[MM];      // 存放参数解向量（女生）
    private static double[] Y;         // 样本中的子女身高
    private static double[] X1;         // 样本中的父亲身高
    private static double[] X2;         // 样本中的母亲身高
    private static double[][] C;   // 系数矩阵


    /**
     * 从excel表格中读取数据
     * @param tableName : 表格名称
     */
    static void FormProblem(String tableName) {
        File file = new File(tableName);
        List<double[]> dataList = Utils.readExcel(file, 3);
        ML = dataList.size();
        Y = new double[ML];
        X1 = new double[ML];
        X2 = new double[ML];
        int i = 0;
        for (double[] d : dataList) {
            X1[i] = d[0];
            X2[i] = d[1];
            Y[i] = d[2];
            i++;
        }
        return;
    }

    // 计算系数矩阵
    static void FormCLEG() {
        C = new double[ML][MM];
        for (int i = 0; i < ML; i++) {
            C[i][0] = 1.0;
            C[i][1] = X1[i];
            C[i][2] = X2[i];
        }
        return;
    }

    /**
     * 训练参数
     */
    static void train() {
        // 1 训练男孩的参数
        // 从Excel表格中读取数据
        FormProblem("boydata.xls");
        // 初始化系数矩阵
        FormCLEG();
        // 计算参数
        System.out.println("男孩参数训练");
        double SERR = CLEG_LSM.SolutionCLEG(C, Y, BoyParams, ML, MM);
        SERR = Math.sqrt(SERR / (ML - MM));     // 开方
        System.out.printf("SERR = %14.6e\n", SERR);
        for(int k = 0; k < MM; k++) {
            System.out.printf("A[%1d] = %10.5f\n",k, BoyParams[k]);
        }
        System.out.printf("男孩身高预测函数： y = %.5f + %.5f * father's height + %.5f * mother's height\n",
                BoyParams[0], BoyParams[1], BoyParams[2]);
        System.out.println("========================================================================");
        // 2. 训练女孩参数
        // 初始化数据
        FormProblem("girldata.xls");
        // 初始化系数矩阵
        FormCLEG();
        // 计算参数
        System.out.println("女孩参数训练");
        SERR = CLEG_LSM.SolutionCLEG(C, Y, GirlParams, ML, MM);
        SERR = Math.sqrt(SERR / (ML - MM));     // 开方
        System.out.printf("SERR = %14.6e\n", SERR);
        for(int k = 0; k < MM; k++) {
            System.out.printf("A[%1d] = %10.5f\n",k, GirlParams[k]);
        }
        System.out.printf("女孩身高预测函数：y = %.5f + %.5f * father's height + %.5f * mother's height\n",
                GirlParams[0], GirlParams[1], GirlParams[2]);

    }

    /**
     * 输出训练结果
     */
    static void show() {
        System.out.printf("男孩身高预测函数：y = %.5f + %.5f * father's height + %.5f * mother's height\n",
                BoyParams[0], BoyParams[1], BoyParams[2]);
        System.out.printf("女孩身高预测函数：y = %.5f + %.5f * father's height + %.5f * mother's height\n",
                GirlParams[0], GirlParams[1], GirlParams[2]);
    }
    /**
     * 预测函数
     * @param father ：父亲身高
     * @param mother ：母亲身高
     */
    static void forecast(double father, double mother) {
        double boy = BoyParams[0] + BoyParams[1] * father + BoyParams[2] * mother;
        double gril = GirlParams[0] + GirlParams[1] * father + GirlParams[2] * mother;
        System.out.printf("父亲身高：%.1fcm\t母亲身高：%.1fcm\t预测儿子身高：%.1fcm\t\t预测女儿身高：%.1fcm\n", father, mother, boy, gril);
    }

    public static void main(String[] args) {
        // 训练数据
        train();
        Scanner sc = new Scanner(System.in);
        String choose;
        double father;
        double mother;
        while (true) {
            System.out.println("=====================身高预测====================");
            System.out.print("是否进行身高预测(按“N”退出，按其他任意键继续)：");
            choose = sc.next();
            if ("N".equals(choose) || "n".equals(choose)) break;

            show();

            System.out.print("\n请输入父亲身高(cm)：");
            father = sc.nextDouble();
            System.out.print("\n请输入母亲身高(cm)：");
            mother = sc.nextDouble();
            forecast(father, mother);
        }
        sc.close();
    }

}
